#include "app.hpp"

void app_layer::app_init(){
    
    std::string path,db,config;

    this->fp->find("sqlite3","path",path);
    this->fp->find("sqlite3","db",db);
    this->fp->find("sqlite3","config",config);

    sqlite(path.c_str(),db.c_str());
    sqlite.init(); //开始初始化数据库,获取数据库的句柄
    if(!sqlite.check_tab(db)) //如果数据表不存在,则创建数据表
        sqlite.config(config);
    else //如果发现数据表存在就查看是否对数据表进行更新
        sqlite.update_sqlite(config);

    this->app_cache.ipc_init();
}

//缓冲区可以被共享到多个进程当中,大概就是32 位系统的 1页的大小 4096Kb,但是只能通过缓冲区操作,数据库
//将这个缓冲层做多进程的内存共享,只要发现缓冲区发生了切实可行的变化,就马上更新数据库,只有写操作

void xsi_ipc::xsi_ipc_init(){
    exception_linux error;
    try
    {
        xsi_ipc_key = ftok(key_path,key_id); //使用的路径必须为全名称路径
        if(xsi_ipc_key == -1)
            throw error;
        switch(type){
            case SEM:
            semun sem_union;
            sem_union.val = 0;
            if((sem_id = semget(xsi_ipc_key,1,0666|IPC_CREAT)) < 0) //设置信号量,设置单个信号量,用于多进程之间进行互斥
                throw error;
            
            if(semctl(sem_id,0,SETVAL,sem_union) == -1)
                throw error;

            break;
            case MSG_QUEUE: //进程之间同行使用的消息队列
               if((msg_queue_id = msgget(xsi_ipc_key,IPC_CREAT|0666)) < 0 )
                    throw error;
                else
                    break;
            case SHM:
                if((shm_id = shmget(xsi_ipc_key,sizeof(cache_mem),0666 | IPC_CREAT)) == -1)
                    throw error;
                
                if((shm_addr = (char*)shmat(shm_id,0,0)) == NULL)
                    throw error;
                
                break;
            default:
                throw error;//可以自定义错误类型
        }
    }
    catch(exception_linux& e)
    {
        ERR("XSI IPC INIT");
    }
}

/*
* 
*/
void xsi_ipc::snd(msg_buf* buf,size_t size){
   exception_linux error;
    try
    {
       switch (type)
       {
       case MSG_QUEUE:
           if(msgsnd(msg_queue_id,(char*)buf,size,IPC_NOWAIT) < 0) //不阻塞直接发送
            throw error;     
       default:
           break;
       }
    }
    catch(exception_linux& e)
    {
        std::cerr << e.what() << '\n';
    }
}

void xsi_ipc::rcv(msg_buf* buf,size_t size){
   exception_linux error;
    try
    {
       switch (type)
       {
       case MSG_QUEUE:
           if(msgrcv(msg_queue_id,(char*)buf,size,0,IPC_NOWAIT) < 0) //不阻塞IPC通道,应该立即返回
                throw error;
       default:
           break;
       }
    }
    catch(exception_linux& e)
    {
        std::cerr << e.what() << '\n';
    }
}

void xsi_ipc::sem_p(){ // 常规的p,v 操作
   exception_linux error;
   sembuf tmp;
   tmp.sem_flg = SEM_UNDO;
   tmp.sem_num = 0;
   tmp.sem_op = -1;

   try
   {
       if(semop(sem_id,&tmp,1) < 0) //只是用了一个信号量
            throw error;
   }
   catch(exception_linux& e)
   {
       std::cerr << e.what() << '\n';
   }
   
}

void xsi_ipc::sem_v(){ //设置信号量集
   exception_linux error;
   sembuf tmp;
   tmp.sem_flg = SEM_UNDO;
   tmp.sem_num = 0;
   tmp.sem_op = 1;

   try
   {
       if(semop(sem_id,&tmp,1) < 0)
            throw error;
   }
   catch(exception_linux& e)
   {
       std::cerr <<  ":" << e.what() << '\n';
   }
}

void xsi_ipc::sem_del(){
    exception_linux error;
    try
    {   
        semun tmp;
        if(semctl(sem_id,0,IPC_RMID,tmp) < 0)
            throw error;
    }
    catch(exception_linux& e)
    {
            std::cerr << e.what() << '\n';
    }    
}

xsi_ipc::~xsi_ipc(){
    switch (type)
    {
    case SEM:
        printp("Rm ipc semid ~ \n");
        sem_del();
        break;
    case MSG_QUEUE:
        msgctl(msg_queue_id,IPC_RMID,NULL);
        break;
    case SHM:
        printp("Rm shmid ~\n");
        shmctl(shm_id,IPC_RMID,NULL); //删除共享内存区间
        break;
    default:
        break;
    }
}

void xsi_ipc::write(char* buf,int offset,int size){
   memcpy(shm_addr+offset,buf,size);
}

void xsi_ipc::read(char*buf,int offset,int size){
    memcpy(buf,shm_addr+offset,size);
}

//TODO:软件缓存层,查看创建是否成功
void app_layer::app_cache_info(){
    for(int i = this->app_cache.zone->begin_pages_full_index ; i < this->app_cache.zone->end_pages_full_index ; i++){
        std::cout << this->app_cache.zone->full_pages[i]->name << std::endl;
    }
}

void xsi_ipc::operator()(const char*kp,int id,XSI_IPC_E t){
    this->key_id = id;
    this->key_path = kp;
    this->type = t;
}

void cache_layer::ipc_init(){
    std::string ipc_path;
    int ipc_id;
    fp->find("cache_layer","fs_path",ipc_path);
    fp->find("cache_layer","key_id",ipc_id);
    
    shm(ipc_path.c_str(),ipc_id,SHM);
    shm.xsi_ipc_init();

    sem(ipc_path.c_str(),ipc_id,SEM);
    sem.xsi_ipc_init();
    shm.write((char*)this->zone,0,sizeof(cache_mem)); //FIXME:将整个内存池拷贝过去,对使用的空间需要重新计算 TODO: 添加异常处理
}

cache_layer::~cache_layer(){
     printp("clear cache_layer ~\n"); //TODO: 清理整个缓存层的空间
}

void cache_layer::cache_layer_info(){ //查看缓存层的信息
    printp("cache_layer_info: %s\n",cache_name.c_str());
}
